<template>
  <div class="cal_con">
    <div v-if="type === 'switch'">
        <div class="cal_header">
          <div class="cal_h_left">
            <div class="cal_h_btn" @click="preYear"> 《{{ year - 1 }}</div>
          </div>

          <div class="cal_h_btn_box">
            <div class="cal_h_btn" :style="{ color:styleConfig.color }" @click="preMonth">《</div>
            <span class="cal_h_time" :style="{ color:styleConfig.color }">{{ year }} 年 </span>
            <span :style="{ color:styleConfig.color }" class="cal_h_time">{{ month }} 月</span>
            <div :style="{ color:styleConfig.color }" class="cal_h_btn" @click="nextMonth">》</div>
          </div>

          <div class="cal_h_left cal_h_right">
            <div class="cal_h_btn" @click="nextYear">{{ year + 1 }}》</div>
          </div>
      </div>
      <div class="cal_month" :style="{ ...slideStyle }">
        <div class="cal_m_weeks">
          <span v-for="w in weeksList" :key="w" :style="{ color:styleConfig.color }" class="cal_m_day_cell">{{ w}}</span>
        </div>

        <div class="cal_m_days">
          <div
            v-for="(ds, index) in monthData"
            :key="index"
            class="cal_m_day_line"
          >
            <div
              v-for="d in ds"
              :key="d.day"
              :class="{
                cal_m_day_cell: d.type === 0,
                isSelitonSelectFirst: mode === 'section' && selectDay[0]?.day === d.day && d.isSelcet,
                isSelitonSelectLast: mode === 'section' && selectDay[1]?.day === d.day && d.isSelcet,
              }"
              class="cal_m_day_cell2"
              :style="{ ...defatulCellColor(d), ...selectStyle(d) }"
              @click="mouseenter(d)"
            >
              <div class="world-box">
                <span>
                {{ d.day}}
              </span>
            
              <span
                v-if="
                  d.day == selectDay[0]?.day &&
                  mode === 'section'
                  && d.isSelcet
                "
              >
                {{ strartWorld }}
              </span>
              <span
                v-if="
                  d.day == selectDay[1]?.day &&
                  mode === 'section'
                  && d.isSelcet
                "
              >
                {{ endWorld }}
              </span>
              </div>
              
            </div>
          </div>
        </div>
      </div>
    </div>
    <div v-else>
       <div class="cal_header cal_header_2">

          <div class="cal_h_btn_box">
            <span class="cal_h_time" :style="{ color:styleConfig.color }">{{ year }} 年 </span>
            <span :style="{ color:styleConfig.color }" class="cal_h_time">{{ month }} 月</span>
          </div>
      </div>
      <div class="cal_month" :style="{ ...slideStyle }">
        <div class="cal_m_weeks">
          <span v-for="w in weeksList" :key="w" :style="{ color:styleConfig.color }" class="cal_m_day_cell">{{ w}}</span>
        </div>

        <div class="cal_m_days" v-swipeup="(e) => vueTouch('上滑', e)"
          v-swipedown="(e) => vueTouch('下滑', e)">
          <div
            v-for="(ds, index) in monthData"
            :key="index"
            class="cal_m_day_line"
          >
            <div
              v-for="d in ds"
              :key="d.day"
              :class="{
                cal_m_day_cell: d.type === 0,
                isSelitonSelectFirst: mode === 'section' && selectDay[0]?.day === d.day && d.isSelcet,
                isSelitonSelectLast: mode === 'section' && selectDay[1]?.day === d.day && d.isSelcet,
              }"
              class="cal_m_day_cell2"
              :style="{ ...defatulCellColor(d), ...selectStyle(d) }"
              @click="mouseenter(d)"
            >
              <div class="world-box">
                <span>
                {{ d.day}}
              </span>
            
              <span
                v-if="
                  d.day == selectDay[0]?.day &&
                  mode === 'section'
                  && d.isSelcet
                "
              >
                {{ strartWorld }}
              </span>
              <span
                v-if="
                  d.day == selectDay[1]?.day &&
                  mode === 'section'
                  && d.isSelcet
                "
              >
                {{ endWorld }}
              </span>
              </div>
              
            </div>
          </div>
        </div>
      </div>
    </div>
    <div v-if="isNo" class="isNo">超出日期范围</div>
  </div>
</template>

<script>
export default {
  name: "Calendar",
  props: {
    date: {
      type: Date,
      default: () => new Date(),
    },
    mode: {
      type: String,
      default: "",
    },
    type: {
      type: String,
      default: "",
    },
    strartWorld: {
      type: String,
      default: "",
    },
    endWorld: {
      type: String,
      default: "",
    },
    styleConfig:{
      type:Object,
      default:()=>{
        return {}
      }
    },
    weeks:{
      type: String,
      default: "",
    },
    maxDate: {
      type: String,
      default: "",
    },
    smallDate: {
      type: String,
      default: "",
    },
    startTime: {
      type: String,
      default: "",
    },
    endTime: {
      type: String,
      default: "",
    },
  },
  data() {
    return {
      selectClass: {
        color: "#fff",
        borderRadius: "4px",
        background: "#3374ff",
      },
      rangeClass: {
        color: "#fff",
        borderRadius: "0px",
        background: "rgb(51, 116, 255,0.45)",
      },
      now: this.date,
      year: 0,
      month: 0,
      monthData: [],
      currentYear: new Date().getFullYear(),
      currentMonth: new Date().getMonth() + 1,
      currentDay: new Date().getDate(),
      selectDay: [],
      isNo: false,
      
    };
  },
  computed: {
    weeksList(){
      return this.weeks.split(',')
    },
    slideStyle() {
      if (this.type === "slide") {
        return {
          height: "400px",
          overflow: "auto",
        };
      }
    },
    nextColor() {
      return (d) => {
        let color =
          d.type == -1 ? "transparent" : d.type == 1 ? "transparent" : "";
        let visibility = d.type == -1 ? "hiden" : d.type == 1 ? "hiden" : "";
        let opacity = d.type == -1 ? 0 : d.type == 1 ? 0 : "";
        return {
          color,
          visibility,
          opacity,
        };
      };
    },
    defatulCellColor() {
      return (d) => {
        let color =
          d.type == -1 ? "transparent" : d.type == 1 ? "transparent" : "";
        let visibility = d.type == -1 ? "hiden" : d.type == 1 ? "hiden" : "";
        let opacity = d.type == -1 ? 0 : d.type == 1 ? 0 : "";
        return {
          color:this.styleConfig.color,
          visibility,
          opacity,
        };
      };
    },
    selectStyle() {
      return (d) => {
        if (this.mode === "select" || this.mode === "multiple") {
          if (d.isSelcet) {
            return this.selectClass;
          } else {
            return {};
          }
        } else {
          if (this.selectDay.length) {
            let currentYear = d.fullYear;
            let currentMonth = d.month >= 10 ? d.month : "0" + d.month;
            let currentDay = d.day >= 10 ? d.day : "0" + d.day;
            let currentDate = `${currentYear}${currentMonth}${currentDay}`;
            let startYear = this.selectDay[0].fullYear;
            let startMonth =
              this.selectDay[0].month >= 10
                ? this.selectDay[0].month
                : "0" + this.selectDay[0].month;
            let startDay =
              this.selectDay[0].day >= 10
                ? this.selectDay[0].day
                : "0" + this.selectDay[0].day;
            let startDate = `${startYear}${startMonth}${startDay}`;
            let endYear = this.selectDay[this.selectDay.length - 1].fullYear;
            let endMonth =
              this.selectDay[this.selectDay.length - 1].month >= 10
                ? this.selectDay[this.selectDay.length - 1].month
                : "0" + this.selectDay[this.selectDay.length - 1].month;
            let endDay =
              this.selectDay[this.selectDay.length - 1].day >= 10
                ? this.selectDay[this.selectDay.length - 1].day
                : "0" + this.selectDay[this.selectDay.length - 1].day;
            let endDate = `${endYear}${endMonth}${endDay}`;
            if (Number(currentDate) === Number(startDate) && d.isSelcet) {
              console.log(1);
              return this.selectClass;
            } else if (Number(currentDate) === Number(endDate) && d.isSelcet) {
              console.log(2);
              return this.selectClass;
            } else if (
              Number(endDate) > Number(currentDate) &&
              Number(currentDate) > Number(startDate)
            ) {
              return this.rangeClass;
            } else {
              return {};
            }
          } else {
            return {};
          }
        }
      };
    },
  },
  mounted() {
    this.setYearMonth(this.now);
    this.generateMonth(this.now);
    this.init();
  },
  methods: {
    vueTouch: function (txt, e) {
      if (txt === "上滑") {
        this.nextMonth();
      } else if (txt === "下滑") {
        this.preMonth();
      }
    },
    init() {
      if (this.mode === "section" && this.startTime && this.endTime) {
        let strart = new Date(this.startTime);
        let end = new Date(this.endTime);
        this.selectDay.push({
          type: 0,
          date: strart,
          fullYear: strart.getFullYear(),
          month: strart.getMonth() + 1,
          day: strart.getDate(),
          isSelcet: true,
        });
        this.selectDay.push({
          type: 0,
          date: end,
          fullYear: end.getFullYear(),
          month: end.getMonth() + 1,
          day: end.getDate(),
          isSelcet: true,
        });
      }
    },
    isDisable(d) {
      let start = Number(this.smallDate.split("-").join(""));
      let end = Number(this.maxDate.split("-").join(""));
      let selectDay = Number(
        `${d.fullYear}${d.month < 10 ? "0" + d.month : d.month}${
          d.day < 10 ? "0" + d.day : d.day
        }`
      );
      if ((start && start > selectDay) || (end && end < selectDay)) {
        this.isNo = true;
        setTimeout(() => {
          this.isNo = false;
        }, 1500);
        return true;
      }
    },
    transformation(date){
      const arr = date.split(',')
      arr[arr.length - 1] = '0.45)'
      return arr.join(',')
    },
    setYearMonth(now) {
      this.year = now.getFullYear();
      this.month = now.getMonth() + 1;
    },
    preYear() {
      let n = this.now;
      let date = new Date(
        n.getFullYear() - 1,
        n.getMonth(),
        n.getDate(),
        n.getHours(),
        n.getMinutes(),
        n.getSeconds(),
        n.getMilliseconds()
      );

      this.setYearMonthInfos(date);
    },
    preMonth() {
      let n = this.now;
      let date = new Date(
        n.getFullYear(),
        n.getMonth() - 1,
        n.getDate(),
        n.getHours(),
        n.getMinutes(),
        n.getSeconds(),
        n.getMilliseconds()
      );

      this.setYearMonthInfos(date);
    },
    nextYear() {
      let n = this.now;
      let date = new Date(
        n.getFullYear() + 1,
        n.getMonth(),
        n.getDate(),
        n.getHours(),
        n.getMinutes(),
        n.getSeconds(),
        n.getMilliseconds()
      );

      this.setYearMonthInfos(date);
    },
    nextMonth() {
      let n = this.now;
      let date = new Date(
        n.getFullYear(),
        n.getMonth() + 1,
        n.getDate(),
        n.getHours(),
        n.getMinutes(),
        n.getSeconds(),
        n.getMilliseconds()
      );

      this.setYearMonthInfos(date);
    },
    setYearMonthInfos(date) {
      this.setYearMonth(date);
      this.generateMonth(date);
      this.now = date;
      this.dateChange();
    },
    generateMonth(date) {
      date.setDate(1);
      // 星期 0 - 6， 星期天 - 星期6
      let weekStart = date.getDay();

      let endDate = new Date(date.getFullYear(), date.getMonth() + 1, 0);
      let dayEnd = endDate.getDate();
      // 星期 0 - 6， 星期天 - 星期6
      let weeEnd = endDate.getDay();

      let milsStart = date.getTime();
      let dayMils = 24 * 60 * 60 * 1000;
      let milsEnd = endDate.getTime() + dayMils;

      let monthDatas = [];
      let current;
      // 上个月的几天
      for (let i = 0; i < weekStart; i++) {
        current = new Date(milsStart - (weekStart - i) * dayMils);
        monthDatas.push({
          type: -1,
          date: current,
          fullYear: current.getFullYear(),
          month: current.getMonth() + 1,
          day: current.getDate(),
          isSelcet: false,
        });
      }
      // 当前月
      for (let i = 0; i < dayEnd; i++) {
        current = new Date(milsStart + i * dayMils);
        monthDatas.push({
          type: 0,
          date: current,
          fullYear: current.getFullYear(),
          month: current.getMonth() + 1,
          day: current.getDate(),
          isSelcet: false,
        });
      }
      // 下个月的几天
      for (let i = 0; i < 6 - weeEnd; i++) {
        current = new Date(milsEnd + i * dayMils);
        monthDatas.push({
          type: 1,
          date: current,
          fullYear: current.getFullYear(),
          month: current.getMonth() + 1,
          day: current.getDate(),
          isSelcet: false,
        });
      }

      this.monthData = [];
      for (let i = 0; i < monthDatas.length; i++) {
        let mi = i % 7;
        if (mi == 0) {
          this.monthData.push([]);
        }
        this.monthData[Math.floor(i / 7)].push(monthDatas[i]);
      }

      // 少于6行，补足6行
      if (this.monthData.length <= 5) {
        milsStart = current.getTime();
        let lastLine = [];
        for (let i = 1; i <= 7; i++) {
          current = new Date(milsStart + i * dayMils);
          lastLine.push({
            type: 1,
            date: current,
            fullYear: current.getFullYear(),
            month: current.getMonth() + 1,
            day: current.getDate(),
          });
        }
        this.monthData.push(lastLine);
      }
    },
    clickRange(d) {
      if (
        Number(
          `${this.selectDay[1].fullYear}${this.selectDay[1].month}${this.selectDay[1].day}`
        ) < Number(`${d.fullYear}${d.month}${d.day}`) ||
        Number(
          `${this.selectDay[1].fullYear}${this.selectDay[0].month}${this.selectDay[0].day}`
        ) < Number(`${d.fullYear}${d.month}${d.day}`)
      ) {
        let day = this.selectDay.pop();
        day.isSelcet = false;
        this.selectDay.push(d);
      } else if (
        Number(
          `${this.selectDay[0].fullYear}${this.selectDay[0].month}${this.selectDay[0].day}`
        ) > Number(`${d.fullYear}${d.month}${d.day}`)
      ) {
        let day = this.selectDay.shift();
        day.isSelcet = false;
        this.selectDay.unshift(d);
      }
      console.log(this.selectDay);
    },
    mouseenter(d, event) {
      if (this.isDisable(d)) {
        return;
      }
      d.isSelcet = !d.isSelcet;
      if (d.isSelcet) {
        if (this.mode === "single") {
          this.selectDay.push(d);
          if (this.selectDay.length > 1) {
            this.selectDay.forEach((item, index) => {
              if (
                `${item.fullYear}${item.month}${item.day}` ===
                  `${d.fullYear}${d.month}${d.day}` &&
                d.isSelcet
              ) {
                item.isSelcet = ture;
              } else {
                item.isSelcet = false;
                this.selectDay.splice(index, 1);
              }
            });
          }
        } else if (this.mode === "multiple") {
          this.selectDay = [...new Set(this.selectDay)];
        } else {
          if (this.selectDay.length === 2) {
            this.clickRange(d);
          } else {
            if (this.selectDay.length === 1) {
              let currentYear = d.fullYear;
              let currentMonth = d.month >= 10 ? d.month : "0" + d.month;
              let currentDay = d.day >= 10 ? d.day : "0" + d.day;
              let currentDate = `${currentYear}${currentMonth}${currentDay}`;
              let endYear = this.selectDay[this.selectDay.length - 1].fullYear;
              let endMonth =
                this.selectDay[this.selectDay.length - 1].month >= 10
                  ? this.selectDay[this.selectDay.length - 1].month
                  : "0" + this.selectDay[this.selectDay.length - 1].month;
              let endDay =
                this.selectDay[this.selectDay.length - 1].day >= 10
                  ? this.selectDay[this.selectDay.length - 1].day
                  : "0" + this.selectDay[this.selectDay.length - 1].day;
              let endDate = `${endYear}${endMonth}${endDay}`;
              if (currentDate < endDate) {
                this.selectDay.unshift(d);
              } else {
                this.selectDay.push(d);
              }
            } else {
              this.selectDay.push(d);
            }
          }
        }
      } else {
        let index = this.selectDay.findIndex((item) => {
          return (
            `${item.fullYear}${item.month}${item.day}` ===
            `${d.fullYear}${d.month}${d.day}`
          );
        });
        if (index >= 0) {
          this.selectDay.splice(index, 1);
        }
      }
      this.$emit("enter", event, this.selectDay);
    },
    dateChange() {
      let fullYear = this.now.getFullYear();
      let month = this.now.getMonth();

      let startDay = new Date(fullYear, month, 1);
      let endDay = new Date(fullYear, month + 1, 0, 23, 59, 59);

      this.$emit("changeMonth", startDay, endDay);
    },
  },
  watch: {
    monthData: {
      // 数据变化时执行的逻辑代码
      handler(newName, oldName) {
        newName.forEach((it) => {
          it.forEach((item) => {
            this.selectDay.forEach((sIt) => {
              if (
                `${sIt.fullYear}${sIt.month}${sIt.day}` ===
                `${item.fullYear}${item.month}${item.day}`
              ) {
                item.isSelcet = sIt.isSelcet;
              }
            });
          });
        });
      },
      // 开启深度监听
      deep: true,
    },
  },
  created() {
    this.selectClass.color = this.styleConfig.selectColor;
    this.selectClass.background = this.styleConfig.selectBg;
    this.rangeClass.color = this.styleConfig.color;
    this.rangeClass.background = this.transformation(this.styleConfig.selectBg);
  },
};
</script>

<style scoped lang="less">
.cal_con {
  width: 100%;
  height: 100%;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;

  color: #606266;
  // border: 1px solid #e4e7ed;
  // box-shadow: 0 2px 12px 0 #0000006e;
  background: #fff;
  // border-radius: 4px;
  margin: auto;

  .cal_header {
    height: 44px;
    padding: 0 5px;
    font-size: 14px;
    line-height: 44px;
    display: flex;
    justify-content: space-between;
    justify-items: center;

    .cal_h_time {
      cursor: pointer;
    }
    .cal_h_time:hover {
      color: #409eff;
    }

    .cal_h_left {
      height: 100%;
      display: flex;

      .cal_h_btn {
        height: 100%;
        cursor: pointer;
      }

      // .cal_h_btn:hover {
      //   background-color: #ebeef5;
      // }

      .cal_h_l_icon {
        height: 8px;
        width: 12px;
        margin: auto;
      }
    }
    .cal_h_right {
      text-align: right;
    }
  }
  .cal_header_2 {
    display: flex;
    justify-content: center;
  }
  .cal_month {
    font-size: 12px;
    text-align: center;
    height: calc(100% - 34px);

    .cal_m_day_cell {
      width: 54px;
      height: 54px;
      line-height: 54px;
      cursor: pointer;
      position: relative;
    }
    .cal_m_day_cell2 {
      width: 54px;
      height: 54px;
      line-height: 54px;
      cursor: pointer;
      position: relative;
    }
    // .cal_m_day_cell:hover {
    //   color: #fff;

    //   border-radius: 4px;
    // }

    .cal_m_weeks {
      height: 30px;
      display: flex;
      justify-content: space-around;
      justify-items: center;
      // box-shadow: 0 0px 12px 0 #0000006e;
    }

    .cal_m_days {
      height: calc(100% - 49px);
      padding: 8px;
      display: flex;
      justify-content: space-around;
      justify-items: center;
      flex-wrap: wrap;
      .cal_m_day_line {
        width: 100%;
        display: flex;
        justify-content: space-around;
        justify-items: center;
      }
    }
  }
}
.cal_h_btn_box {
  display: flex;
}
.top_weeks {
  position: sticky;
  top: 0px;
}
.isSelitonSelectFirst {
    border-radius: 4px 0 0 4px!important;
  }
  .isSelitonSelectLast {
    border-radius: 0 4px 4px 0!important;
  }
.world-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  position: relative;
  span {
    height: 15px;
  }
}
.isNo {
  position: fixed;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1001;
  padding: 4px 10px;
  border-radius: 4px;
  background-color: rgba(0, 0, 0, 0.75);
  color: #fff;
}
</style>
